<?php

namespace common\observer;


use common\service\StatusService;
use think\Hook;
use Webman\Stomp\Client;
use common\model\UserModel;
use support\SingletonTrait;
use common\model\TaskModel;
use common\model\EntityModel;
use common\service\TaskService;
use common\service\UserService;
use common\service\ChatService;
use common\service\CommonService;
use common\service\EntityService;
use common\service\MessageService;
use common\model\OrderTaskListModel;
use common\model\EntityEpisodeRelationModel;
use teamones\dbeventObserver\interfaces\SplSubject;
use teamones\dbeventObserver\interfaces\SplObserver;

/**
 * 监听实体的关联关系变化
 * 自动检查能否组装
 */
class RelationChangeAutoAssembleCheck implements SplObserver
{
    use SingletonTrait;

    /**
     * @param SplSubject $subject
     * @return void
     */
    function update(SplSubject $subject): void
    {
        $entity = $subject->getSubjectData();
        $updateData = $subject->getSplUpdateData();

        $currentModule = module_by_id($entity['module_id']);
        if (empty($currentModule)) {
            return;
        }
        $listenFields = [$currentModule['code'] . '_asset', $currentModule['code'] . '_level'];
        $changedKey = array_keys($updateData);
        $changedListenKey = array_intersect($changedKey, $listenFields);
        if (empty($changedListenKey)) {
            return;
        }

        try {
            $this->checkEntityTaskAssembleTaskAsync($entity['id']);
        } catch (\Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
        try {
            $this->pushRelationChangeMessage($subject, $changedListenKey);
        } catch (\Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
    }

    /**
     * 异步去检查实体的所有任务的组装状态
     * @param int $entityId
     * @return void
     */
    public function checkEntityTaskAssembleTaskAsync(int $entityId)
    {
        // 排除掉实体已取消的工序
        $closedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();
        $taskIdList = model(TaskModel::class)
            ->where(['entity_id' => $entityId, 'step_type' => 'step',])
            ->where(["json->>'$.task_status'" => ['NEQ', $closedStatus['id']]])
            ->field('id')
            ->column('id');
        foreach ($taskIdList as $index => $taskId) {
            Client::send('task_assemble_check', build_queue_data_with_xu(['task_id' => $taskId]), $index + 1);
        }
    }

    /**
     * 推送关联发生变化通知消息
     * @param SplSubject $subject
     * @param $changedListenKey
     * @return void
     * @throws \think\Exception
     */
    private function pushRelationChangeMessage(SplSubject $subject, $changedListenKey)
    {
        $entity = $subject->getSubjectData();
        $moduleCode = module_by_id($entity['module_id'])['code'];
        if (!in_array($moduleCode, ['level', 'shot'])) {
            return;
        }
        $updateData = $subject->getSplUpdateData();
        $old = $subject->getSplOldData();
        if (!isset($old['json'])) {
            return;
        }
        $listenKeyList = [
            $moduleCode . '_asset',
            $moduleCode . '_level',
        ];
        $jsonFields = json_decode($old['json'], true);

        $added = [];
        $deleted = [];
        foreach ($changedListenKey as $key) {
            if (!in_array($key, $listenKeyList)) {
                continue;
            }

            $old = $jsonFields[$key] ?? '';
            $new = $updateData[$key];
            $oldIdList = explode(',', $old);
            $oldIdList = array_filter(array_map('intval', $oldIdList));

            $newIdList = explode(',', $new);
            $newIdList = array_filter(array_map('intval', $newIdList));

            $tempAdded = array_diff($newIdList, $oldIdList);
            $tempDeleted = array_diff($oldIdList, $newIdList);

            if (!empty($tempAdded)) {
                $added = array_merge($added, $tempAdded);
            }
            if (!empty($tempDeleted)) {
                $deleted = array_merge($deleted, $tempDeleted);
            }
        }
        // 同步镜头和资产的剧集关系
        $this->entityRelationChangedEpisodeRelationSyncToAsset($subject, $moduleCode, $added, $deleted);
        $hookData = [
            'type' => 'entity_relation_change',
            'data' => [
                'entity' => $entity,
                'module_code' => $moduleCode,
                'added' => $added,
                'deleted' => $deleted,
            ],
        ];
        Hook::listen('entity_change_after', $hookData);
    }

    /**
     * 镜头实体关联发生变化 同步剧集关系到资产
     * @param SplSubject $subject
     * @param $moduleCode
     * @param array $added
     * @param array $deleted
     * @return void
     * @throws \think\Exception
     */
    private function entityRelationChangedEpisodeRelationSyncToAsset(SplSubject $subject, $moduleCode, array $added, array $deleted)
    {
        if ($moduleCode != 'shot') {
            return;
        }

        $shot = $subject->getSubjectData();
        if (empty($shot['initial_episode_code'])) {
            return;
        }
        $episode = model(EntityModel::class)
            ->where(['project_id' => $shot['project_id'], 'module_id' => module_by_code('episode')['id'], 'code' => $shot['initial_episode_code']])
            ->find();
        if (empty($episode)) {
            return;
        }
        // 组装是否存在数据检查 筛选条件
        $existFilter = [];
        $changed = [
            ...$added, ...$deleted
        ];
        if (empty($changed)) {
            return;
        }
        $changedEntityList = model(EntityModel::class)->where(['id' => ['IN', implode(',', $changed)]])->select();

        foreach ($changedEntityList as &$changedEntity) {
            $changedEntity = CommonService::appendJsonFields($changedEntity);
            $currentModuleCode = module_by_id($changedEntity['module_id'])['code'];
            $changedEntity['design_id'] = 0;
            if (!empty($changedEntity[$currentModuleCode . '_design']) && $changedEntity[$currentModuleCode . '_design'] > 0) {
                $changedEntity['design_id'] = $changedEntity[$currentModuleCode . '_design'];
                $existFilter[] = [
                    'entity_id' => $changedEntity[$currentModuleCode . '_design'],
                    'episode_id' => $episode['id'],
                    'showings_number' => $shot['showings_number'],
                ];
            }
            $existFilter[] = [
                'entity_id' => $changedEntity['id'],
                'episode_id' => $episode['id'],
                'showings_number' => $shot['showings_number'],
            ];
        }

        if (empty($existFilter)) {
            return;
        }
        $existFilter['_logic'] = 'OR';

        $designIdList = array_filter(array_column($changedEntityList, 'design_id'));
        $designList = [];
        if (!empty($designIdList)) {
            $designFields = [
                'id',
                'project_id',
                'name',
                'design_category',
                'design_perform_species'
            ];
            $designList = model(EntityModel::class)
                ->alias('design')
                ->where(['design.id' => ['IN', implode(',', $designIdList)]])
                ->field(transform_custom_fields($designFields, 'design'))
                ->select();
            $designList = array_column($designList, null, 'id');
        }

        // 组装待插入数据和待删除数据
        $existCheckList = model(EntityEpisodeRelationModel::class)->where($existFilter)->select();
        $existCheckMap = [];
        foreach ($existCheckList as $existCheck) {
            $key = $existCheck['episode_id'] . $existCheck['showings_number'] . $existCheck['entity_id'];
            $existCheckMap[$key] = $existCheck;
        }
        unset($changedEntity);
        $scriptFillBackData = [];
        $addAllList = $deletedEntityEpisodeRelationIdList = [];
        foreach ($changedEntityList as $changedEntity) {
            $key = $episode['id'] . $shot['showings_number'] . $changedEntity['id'];
            $designKey = $episode['id'] . $shot['showings_number'] . $changedEntity['design_id'];

            if (in_array($changedEntity['id'], $added)) {
                if (!isset($existCheckMap[$key])) {
                    $addAllList[] = [
                        'entity_id' => $changedEntity['id'],
                        'entity_module_id' => $changedEntity['module_id'],
                        'episode_id' => $episode['id'],
                        'created' => time(),
                        'project_id' => $shot['project_id'],
                        'showings_number' => $shot['showings_number'],
                    ];
                }
                if (!isset($existCheckMap[$designKey])) {
                    $addAllList[] = [
                        'entity_id' => $changedEntity['design_id'],
                        'entity_module_id' => $changedEntity['module_id'],
                        'episode_id' => $episode['id'],
                        'created' => time(),
                        'project_id' => $shot['project_id'],
                        'showings_number' => $shot['showings_number'],
                    ];
                    if (isset($designList[$changedEntity['design_id']])) {
                        $design = $designList[$changedEntity['design_id']];
                        $scriptFillBackData[] = [
                            "project_id" => $design['project_id'],
                            "episode_id" => $episode['id'],
                            "name" => $design['name'],
                            "design_category" => $design['design_category'] ?? '',
                            "showings_number" => $shot['showings_number'],
                            "design_perform_species" => $design['design_perform_species']
                        ];
                    }
                }

            }
//            elseif (in_array($changedEntity['id'], $deleted)) {
//                if (isset($existCheckMap[$key])) {
//                    $deletedEntityEpisodeRelationIdList[] = $existCheckMap[$key]['id'];
//                }
//                if (isset($existCheckMap[$designKey])) {
//                    $deletedEntityEpisodeRelationIdList[] = $existCheckMap[$designKey]['id'];
//                }
//            }
        }

        // 插入剧集关联关系
        if (!empty($addAllList)) {
            try {
                model(EntityEpisodeRelationModel::class)->addAll($addAllList, [], true);
            } catch (\Throwable $e) {
                trace(format_exception_info($e), 'ERR');
            }
        }
        // 删除剧集关联关系
//        if (!empty($deletedEntityEpisodeRelationIdList)) {
//            try {
//                model(EntityEpisodeRelationModel::class)
//                    ->where(['id' => ['IN', implode(',', $deletedEntityEpisodeRelationIdList)]])
//                    ->delete();
//            } catch (\Throwable $e) {
//                trace(format_exception_info($e), 'ERR');
//            }
//        }
        // 填充剧集关系到剧本
        if (!empty($scriptFillBackData)) {
            Client::send('fill_back_script_detailed_list_data', build_queue_data_with_xu(['data' => $scriptFillBackData]));
        }
    }
}
